package com.smedi.ismedi.progress.core.port.adapter.persistence.repository.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import com.smedi.ismedi.authority.starter.util.AuthorityUtil;
import com.smedi.ismedi.constructionproject.api.dto.response.ProjectBasicResponse;
import com.smedi.ismedi.progress.api.dto.response.FileResponse;
import com.smedi.ismedi.progress.core.application.command.*;
import com.smedi.ismedi.progress.core.application.convert.AppConverter;
import com.smedi.ismedi.progress.core.domain.aggregatemodel.*;
import com.smedi.ismedi.progress.core.domain.dto.FileQuery;
import com.smedi.ismedi.progress.core.domain.dto.PersonQuery;
import com.smedi.ismedi.progress.core.domain.repository.ConstructionLogRepository;
import com.smedi.ismedi.progress.core.domain.repository.FileRepository;
import com.smedi.ismedi.progress.core.domain.repository.PersonRepository;
import com.smedi.ismedi.progress.core.infrastructure.constant.ConstantField;
import com.smedi.ismedi.progress.core.port.adapter.convert.AdapterConverter;
import com.smedi.ismedi.progress.core.port.adapter.persistence.model.*;
import com.smedi.ismedi.progress.core.port.adapter.persistence.mybatis.mapper.ConstructionLogAttachmentImageMapper;
import com.smedi.ismedi.progress.core.port.adapter.persistence.mybatis.mapper.ConstructionLogDetailMapper;
import com.smedi.ismedi.progress.core.port.adapter.persistence.mybatis.mapper.ConstructionLogMapper;
import com.smedi.ismedi.progress.core.port.adapter.service.ProjectProgressService;
import com.smedi.ismedi.progress.core.port.adapter.service.TaskRemoteService;
import com.smedi.ismedi.web.starter.common.ResponseData;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.smedi.ismedi.progress.core.infrastructure.constant.ConstantField.PROJECT_TYPE;

/**
 * 施工日志仓库实现类
 *
 * @author liaojiajie
 * @date 2022/11/22 10:28
 */

@Service
@AllArgsConstructor
public class ConstructionLogRepositoryImpl implements ConstructionLogRepository {
    private final ConstructionLogMapper constructionLogMapper;
    private final ConstructionLogDetailMapper constructionLogDetailMapper;
    private final ConstructionLogAttachmentImageMapper constructionLogAttachmentImageMapper;
    private final FileRepository fileRepository;
    private final PersonRepository personRepository;
    private final AppConverter appConverter;
    private final ProjectProgressService projectProgressService;
    private final AdapterConverter adapterConverter;
    private final AuthorityUtil authorityUtil;
    private final TaskRemoteService taskRemoteService;


    @Override
    public Page<ConstructionLog> getConstructionLogList(ConstructionLogListQuery constructionLogListQuery) {
        Page<ConstructionLogEntity> page = new Page<>(constructionLogListQuery.getOffset(), constructionLogListQuery.getPageSize());
        ResponseData<List<ProjectBasicResponse>> projectList = new ResponseData<>();
        LambdaQueryWrapper<ConstructionLogEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (PROJECT_TYPE.equals(constructionLogListQuery.getType())){
            lambdaQueryWrapper.eq(ObjectUtils.isNotNull(constructionLogListQuery.getOrganizationOrProjectId()),ConstructionLogEntity::getProjectId,constructionLogListQuery.getOrganizationOrProjectId());
        }else {
            //判断有无选择主体院
            if (constructionLogListQuery.getMainCourtyardId() == null) {
                projectList = projectProgressService.getProjectList(constructionLogListQuery.getOrganizationOrProjectId());
            }
            if (constructionLogListQuery.getMainCourtyardId() != null) {
                projectList = projectProgressService.getProjectList(constructionLogListQuery.getMainCourtyardId());
            }
            if (projectList.getData().size() > 0) {
                List<Long> projectIds = projectList.getData().stream().map(ProjectBasicResponse::getProjectId).collect(Collectors.toList());
                lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(projectIds), ConstructionLogEntity::getProjectId, projectIds);
            } else {
                return new Page<>();
            }
            //如果 条件有选项目
            lambdaQueryWrapper.eq(ObjectUtils.isNotNull(constructionLogListQuery.getProjectId()), ConstructionLogEntity::getProjectId, constructionLogListQuery.getProjectId());
        }
        String recordStartTime = constructionLogListQuery.getRecordStartTime() + " 00:00:00";
        String recordEndTime = constructionLogListQuery.getRecordEndTime() + " 23:59:59";
        lambdaQueryWrapper.between(ObjectUtils.isNotNull(constructionLogListQuery.getLogStartTime()),ConstructionLogEntity::getLogDate,constructionLogListQuery.getLogStartTime(),constructionLogListQuery.getLogEndTime());
        lambdaQueryWrapper.between(ObjectUtils.isNotNull(constructionLogListQuery.getRecordStartTime()),ConstructionLogEntity::getRecordTime,recordStartTime,recordEndTime);
        lambdaQueryWrapper.like(StringUtils.isNotBlank(constructionLogListQuery.getRecordUser()), ConstructionLogEntity::getRecordUser, constructionLogListQuery.getRecordUser());
        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(constructionLogListQuery.getStatus()),ConstructionLogEntity::getStatus,constructionLogListQuery.getStatus());
        lambdaQueryWrapper.orderByDesc(ConstructionLogEntity::getLogDate);
        lambdaQueryWrapper.orderByDesc(ConstructionLogEntity::getRecordTime);
        Page<ConstructionLogEntity> constructionLogEntityPage = constructionLogMapper.selectPage(page, lambdaQueryWrapper);
        Page<ConstructionLog> constructionLogPage = adapterConverter.constructionLogEntityPageToConstructionLog(constructionLogEntityPage);
        if(PROJECT_TYPE.equals(constructionLogListQuery.getType())){
            ProjectBasicResponse project = projectProgressService.getProject(constructionLogListQuery.getOrganizationOrProjectId());
            constructionLogPage.getRecords().forEach(v->{
                v.setProjectName(project.getProjectName());
            });
        }else{
            List<ProjectBasicResponse> finalProjectList = projectList.getData();
            constructionLogPage.getRecords().forEach(v->{
                for (ProjectBasicResponse project: finalProjectList) {
                    if (v.getProjectId().equals(project.getProjectId())){
                        v.setProjectName(project.getProjectName());
                        break;
                    }
                }
            });
        }

        return constructionLogPage;
    }

    @Override
    public ConstructionLogDetail getConstructionLogDetail(ConstructionLogDetailQuery constructionLogDetailQuery,List<Person> personList) {
        LambdaQueryWrapper<ConstructionLogEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        ProjectBasicResponse project = projectProgressService.getProject(constructionLogDetailQuery.getProjectId());
        List<ProgressFile> fileResponseList = new ArrayList<>();
        //编辑和导出不改 状态
        if (1 != constructionLogDetailQuery.getType()) {
            boolean flag = personList.stream().filter(m -> m.getId().equals(authorityUtil.getPersonId())).findAny().isPresent();
            //项目经理查看 改变 状态
            if (flag) {
                LambdaUpdateWrapper<ConstructionLogEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                lambdaUpdateWrapper.eq(ObjectUtils.isNotNull(constructionLogDetailQuery.getId()), ConstructionLogEntity::getId, constructionLogDetailQuery.getId());
                lambdaUpdateWrapper.ne(ConstructionLogEntity::getStatus,1);
                lambdaUpdateWrapper.set(ConstructionLogEntity::getReadingStatus, 2).set(ConstructionLogEntity::getStatus, 3);
                constructionLogMapper.update(null, lambdaUpdateWrapper);
                //改变 处理状态
                taskRemoteService.editTask(TaskRecordEditCommand.builder()
                        .sourceFromId(constructionLogDetailQuery.getId())
                        .taskType(ConstantField.CONSTRUCTION_TYPE)
                        .taskName(ConstantField.CONSTRUCTION_REVIEW)
                        .taskStatus("已完成")
                        .oldStatus(new ArrayList<>(Collections.singletonList("进行中")))
                        .finishTime(LocalDateTime.now())
                        .build());
            }
        }
        //获取施工项目经理 名称
        List<String> Name = personList.stream().distinct().map(Person::getName).collect(Collectors.toList());
        String projectManager = org.apache.commons.lang3.StringUtils.strip(Name.toString(), "[]");

        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(constructionLogDetailQuery.getId()),ConstructionLogEntity::getId,constructionLogDetailQuery.getId());
        ConstructionLogEntity constructionLogEntity = constructionLogMapper.selectOne(lambdaQueryWrapper);

        LambdaQueryWrapper<ConstructionLogDetailEntity> logDetailEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
        logDetailEntityLambdaQueryWrapper.eq(ObjectUtils.isNotNull(constructionLogDetailQuery.getId()),ConstructionLogDetailEntity::getConstructionLogId,constructionLogDetailQuery.getId());
        List<ConstructionLogDetailEntity> constructionLogDetailEntities = constructionLogDetailMapper.selectList(logDetailEntityLambdaQueryWrapper);
        List<ConstructionLogContent> constructionLogContents = adapterConverter.constructionLogDetailEntitiesToconstructionLogContent(constructionLogDetailEntities);

        LambdaQueryWrapper<ConstructionLogAttachmentImageEntity> imageEntityLambdaQueryWrapper =  new LambdaQueryWrapper<>();
        imageEntityLambdaQueryWrapper.eq(ObjectUtils.isNotNull(constructionLogDetailQuery.getId()),ConstructionLogAttachmentImageEntity::getConstructionLogId,constructionLogDetailQuery.getId());
        List<ConstructionLogAttachmentImageEntity> constructionLogAttachmentImageEntities = constructionLogAttachmentImageMapper.selectList(imageEntityLambdaQueryWrapper);
        if (CollectionUtils.isNotEmpty(constructionLogAttachmentImageEntities)){
            List<String> signKeys = constructionLogAttachmentImageEntities.stream().map(ConstructionLogAttachmentImageEntity::getSignKey).collect(Collectors.toList());
            Map<String, ConstructionLogAttachmentImageEntity> signKeyMap = constructionLogAttachmentImageEntities.stream().collect(Collectors.toMap(ConstructionLogAttachmentImageEntity::getSignKey, entity->entity, (old, newObj) -> newObj));
            List<File> fileList = fileRepository.getFileList(FileQuery.builder().signKeys(signKeys).build());
            if (CollectionUtils.isNotEmpty(fileList)) {
                Map<String, File> fileSignKeyMap = fileList.stream().collect(Collectors.toMap(File::getSignKey, entity->entity, (old, newObj) -> newObj));
                //防止乱序
                for (String signKey: signKeys) {
                    File f = fileSignKeyMap.get(signKey);
                    fileResponseList.add(ProgressFile.builder()
                            .name(f.getName())
                            .extName(f.getExtName())
                            .signKey(f.getSignKey())
                            .aliasName(signKeyMap.get(f.getSignKey()).getAliasName())
                            .url(f.getUrlOut())
                            .build());
                }
            }

        }
        if (ObjectUtils.isNotNull(constructionLogEntity) && ObjectUtils.isNotNull(project)){
            ConstructionLogDetail constructionLogDetail = ConstructionLogDetail.builder().id(constructionLogEntity.getId()).projectId(constructionLogEntity.getProjectId())
                    .projectName(project.getProjectName()).projectManager(projectManager).recordUser(constructionLogEntity.getRecordUser())
                    .recordTime(constructionLogEntity.getRecordTime()).logDate(constructionLogEntity.getLogDate()).weather(constructionLogEntity.getWeather())
                    .readingStatus(constructionLogEntity.getReadingStatus()).mechanicalArrange(constructionLogEntity.getMechanicalArrange())
                    .materialsRecord(constructionLogEntity.getMaterialsRecord()).accidentDealMethods(constructionLogEntity.getAccidentDealMethods())
                    .otherSpecialSituation(constructionLogEntity.getOtherSpecialSituation())
                    .constructionLogContents(constructionLogContents).file(fileResponseList).build();
            if(!personList.isEmpty()){
                constructionLogDetail.setEmployeeNum(personList.get(0).getEmployeeNum());
            }
            return constructionLogDetail;
        }
       return null;
    }

    @Override
    public List<ConstructionLogWeather> constructionContext(ConstructionLogQuery constructionLogQuery) {
        List<ConstructionLogEntity> constructionLogs = constructionLogMapper.queryConstructionLogByProjectId(constructionLogQuery);
        List<ConstructionLogWeather> constructionLogWeathers = new ArrayList<>();
        constructionLogs.forEach(v->{
            constructionLogWeathers.add(ConstructionLogWeather.builder()
            .logDate(v.getLogDate())
            .existsRecord(true)
            .weather(v.getWeather())
            .build());
        });
        // 30天内没填记录的 默认为false
        for (int i = 0; i < 30; i++) {
            LocalDate date = LocalDate.now().plusDays(-i);
            if (constructionLogWeathers.stream().filter(x -> date.equals(x.getLogDate())).count() == 0) {
                ConstructionLogWeather constructionLogWeather = new ConstructionLogWeather();
                constructionLogWeather.setLogDate(date);
                constructionLogWeather.setExistsRecord(false);
                constructionLogWeathers.add(constructionLogWeather);
            }
        }
        return constructionLogWeathers.stream().sorted(Comparator.comparing(ConstructionLogWeather::getLogDate)).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public ConstructionLogSaveAndDraft saveReportAndDetial(ConstructionLogSaveAndDraft constructionLogSaveAndDraft) {
        ConstructionLogEntity constructionLogs = adapterConverter.constructionLogSaveAndDraftToConstructionLogEntity(constructionLogSaveAndDraft);
        constructionLogs.setRecordUser(authorityUtil.getLoginAccess().getLastName());
        constructionLogs.setRecordTime(LocalDateTime.now());
        List<ConstructionLogDetailEntity> constructionLogDetail = new ArrayList<>();
        // 插入 详情表
        if (null != constructionLogSaveAndDraft.getConstructionLogContents()){
            constructionLogDetail = adapterConverter.constructionLogContentsToConstructionLogDetailEntity(constructionLogSaveAndDraft.getConstructionLogContents());
        }
        if (ObjectUtils.isNull(constructionLogSaveAndDraft.getId())) {
            constructionLogs.setCreatedUserId(authorityUtil.getPersonId());
            constructionLogs.setCreatedDate(LocalDateTime.now());
            constructionLogMapper.insert(constructionLogs);
            // 插入 详情表
            constructionLogDetail.forEach(v->{
                v.setConstructionLogId(constructionLogs.getId());
                v.setCreatedDate(LocalDateTime.now());
                v.setCreatedUserId(authorityUtil.getPersonId());
            });
        }
        if (ObjectUtils.isNotNull(constructionLogSaveAndDraft.getId())) {
            constructionLogs.setLatestUpdatedDate(LocalDateTime.now());
            constructionLogs.setLatestUpdatedUserId(authorityUtil.getPersonId());
            constructionLogMapper.updateById(constructionLogs);
            LambdaQueryWrapper<ConstructionLogDetailEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(ObjectUtils.isNotNull(constructionLogSaveAndDraft.getId()), ConstructionLogDetailEntity::getConstructionLogId,constructionLogSaveAndDraft.getId());
            constructionLogDetailMapper.delete(lambdaQueryWrapper);
            LambdaQueryWrapper<ConstructionLogAttachmentImageEntity> lambdaImageWrapper = new LambdaQueryWrapper<>();
            lambdaImageWrapper.eq(ObjectUtils.isNotNull(constructionLogSaveAndDraft.getId()),ConstructionLogAttachmentImageEntity::getConstructionLogId,constructionLogSaveAndDraft.getId());
            constructionLogAttachmentImageMapper.delete(lambdaImageWrapper);
            // 先删除对应的详情表和附件表
            constructionLogDetail.forEach(v->{
                v.setConstructionLogId(constructionLogSaveAndDraft.getId());
                v.setLatestUpdatedDate(LocalDateTime.now());
                v.setLatestUpdatedUserId(authorityUtil.getPersonId());
            });
        }
        if (!constructionLogDetail.isEmpty()){
            constructionLogDetailMapper.insertBath(constructionLogDetail);
        }
        // 插入 附件表
        if (CollectionUtils.isNotEmpty(constructionLogSaveAndDraft.getFileList())){
            constructionLogSaveAndDraft.getFileList().forEach(image->{
                constructionLogAttachmentImageMapper.insert(ConstructionLogAttachmentImageEntity.builder()
                        .constructionLogId(constructionLogs.getId())
                        .signKey(image.getAttachmentKey())
                        .aliasName(image.getAliasName())
                        .build());
            });
        }
        return adapterConverter.constructionLogsToConstructionLogSaveAndDraft(constructionLogs);
    }

    @Override
    public ConstructionLogSaveAndDraft getConstructionLogOne(ConstructionLogSaveAndDraft constructionLog) {
        LambdaQueryWrapper<ConstructionLogEntity> constructionLogWrapper = new LambdaQueryWrapper<>();
        constructionLogWrapper.eq(ObjectUtils.isNotNull(constructionLog.getId()), ConstructionLogEntity::getId, constructionLog.getId());
        ConstructionLogEntity constructionLogEntity = constructionLogMapper.selectOne(constructionLogWrapper);
        ConstructionLogSaveAndDraft constructionLogSaveAndDraft = adapterConverter.constructionLogEntityToConstructionLogSaveAndDraft(constructionLogEntity);
        return constructionLogSaveAndDraft;
    }

    @Override
    @Transactional
    public void updateConstructionLog(ConstructionLogSaveAndDraft constructionLogQuery) {
        ConstructionLogEntity constructionLogs = adapterConverter.constructionLogSaveAndDraftToConstructionLogEntity(constructionLogQuery);
        constructionLogMapper.updateById(constructionLogs);
    }

    @Override
    public ConstructionLogEntity getConstructionLog(ConstructionLogSaveAndDraft constructionLogSaveAndDraft) {
        LambdaQueryWrapper<ConstructionLogEntity> constructionLogWrapper = new LambdaQueryWrapper<>();
        constructionLogWrapper.eq(ObjectUtils.isNotNull(constructionLogSaveAndDraft.getProjectId()), ConstructionLogEntity::getProjectId, constructionLogSaveAndDraft.getProjectId());
        constructionLogWrapper.eq(ObjectUtils.isNotNull(constructionLogSaveAndDraft.getLogDate()), ConstructionLogEntity::getLogDate, constructionLogSaveAndDraft.getLogDate());
        ConstructionLogEntity constructionLogEntity = constructionLogMapper.selectOne(constructionLogWrapper);
        return constructionLogEntity;
    }

    @Override
    public ConstructionLog getConstructionLogAPPList(ConstructionLogListQuery constructionLogListQuery, List<Person> personList) {
        LambdaQueryWrapper<ConstructionLogEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (ObjectUtils.isNotNull(constructionLogListQuery.getProjectId())){
            lambdaQueryWrapper.eq(ConstructionLogEntity::getProjectId,constructionLogListQuery.getProjectId());
        }else {
            lambdaQueryWrapper.eq(ObjectUtils.isNotNull(constructionLogListQuery.getOrganizationOrProjectId()),ConstructionLogEntity::getProjectId,constructionLogListQuery.getOrganizationOrProjectId());
        }
        lambdaQueryWrapper.eq(ObjectUtils.isNotNull(constructionLogListQuery.getLogStartTime()),ConstructionLogEntity::getLogDate,constructionLogListQuery.getLogStartTime());
        ConstructionLogEntity constructionLogEntity = constructionLogMapper.selectOne(lambdaQueryWrapper);
        ConstructionLog constructionLog = adapterConverter.constructionLogEntityOneToConstructionLog(constructionLogEntity);

        //获取施工项目经理 名称
        List<String> Name = personList.stream().distinct().map(Person::getName).collect(Collectors.toList());
        String projectManager = org.apache.commons.lang3.StringUtils.strip(Name.toString(), "[]");

        if (StringUtils.isNotBlank(projectManager) && ObjectUtils.isNotNull(constructionLog)){
            constructionLog.setProjectManager(projectManager);
        }
        return constructionLog;
    }

    @Override
    public Integer findConstructionLog(String firstDay, Long projectId) {
        LambdaQueryWrapper<ConstructionLogEntity> constructionLogEntity = new LambdaQueryWrapper<>();
        constructionLogEntity.eq(ObjectUtils.isNotNull(firstDay), ConstructionLogEntity::getLogDate, firstDay);
        constructionLogEntity.eq(ObjectUtils.isNotNull(projectId), ConstructionLogEntity::getProjectId, projectId);
        return constructionLogMapper.selectCount(constructionLogEntity);
    }
}
